package org.coode.annotate;

import org.protege.editor.owl.model.OWLModelManager;
import org.semanticweb.owlapi.model.*;
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.io.*;
import org.semanticweb.owlapi.util.SimpleIRIMapper;

import javax.swing.*;
import javax.swing.border.EtchedBorder;
import javax.swing.text.JTextComponent;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URI;
import java.net.UnknownHostException;
import java.util.Map;

/*
* Copyright (C) 2007, University of Manchester
* 
* Modifications to the initial code base are copyright of their
* respective authors, or their employers as appropriate.  Authorship
* of the modifications may be determined from the ChangeLog placed at
* the end of this file.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.

* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.

* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
*/

/**
 * Author: Nick Drummond<br>
 * http://www.cs.man.ac.uk/~drummond/<br><br>
 * <p/>
 * The University Of Manchester<br>
 * Bio Health Informatics Group<br>
 * Date: Aug 16, 2007<br><br>
 */
public class TemplateRow {

    private JComponent editor;

    private TemplateModel model;

    private OWLAnnotationAssertionAxiom annotAxiom;
    private OWLAnnotationProperty property;
    private OWLAnnotationSubject subject;

    private FocusListener focusListener = new FocusAdapter(){
        public void focusLost(FocusEvent focusEvent) {
            updateAnnotation();
        }
    };

    private ActionListener acceptAction = new ActionListener(){
        public void actionPerformed(ActionEvent actionEvent) {
            updateAnnotation();
            editor.transferFocus();
        }
    };


    public TemplateRow(OWLAnnotationAssertionAxiom annotAxiom, TemplateModel model) {
        this(annotAxiom.getSubject(), annotAxiom.getAnnotation().getProperty(),  model);
        this.annotAxiom = annotAxiom;
        reload(annotAxiom.getAnnotation().getValue());
    }

    // when the editor exists without a supporting axiom
    public TemplateRow(OWLAnnotationSubject subject, OWLAnnotationProperty property, TemplateModel model) {
        super();
        this.model = model;
        this.subject = subject;
        this.property = property;
    }

    public OWLAnnotationProperty getProperty(){
        return property;
    }


    private void updateAnnotation() {

        final OWLModelManager mngr = model.getOWLModelManager();

        OWLAnnotationAssertionAxiom newAxiom = null;
        OWLLiteral newValue = getValue();
        if (newValue != null){
            newAxiom = mngr.getOWLDataFactory().getOWLAnnotationAssertionAxiom(property, subject, newValue);
        }

        List<OWLOntologyChange> changes = new ArrayList<OWLOntologyChange>();

        if (annotAxiom != null){
            if (!annotAxiom.getAnnotation().getValue().equals(newValue)){
                for (OWLOntology ont : mngr.getActiveOntologies()){
                    if (ont.containsAxiom(annotAxiom)){
                        changes.add(new RemoveAxiom(ont, annotAxiom));
                        if (newAxiom != null){
                            changes.add(new AddAxiom(ont, newAxiom));
                        }
                    }
                }
            }
        }
        else{
            if (newAxiom != null){
                changes.add(new AddAxiom(mngr.getActiveOntology(), newAxiom));
            }
        }

        model.requestApplyChanges(changes);

        annotAxiom = newAxiom;
    }

    // all of this should be here or in the model
    public void setValue(OWLObject value) {
        reload(value);
        updateAnnotation();
    }


    private void reload(OWLObject value) {
        EditorType type = model.getComponentType(property);

        switch(type){
            case text:      // FALLTHROUGH
            case multiline:
                if (value == null){
                    ((JTextComponent) getEditor()).setText("");
                }
                else{
                    String rendering;
                    if (value instanceof OWLLiteral){
                        rendering = ((OWLLiteral)value).getLiteral();
                    }
                    else{
                        rendering = value.toString();
                    }
                    ((JTextComponent) getEditor()).setText(rendering);
                }
                break;
            case combo:
                ((JComboBox) getEditor()).setSelectedItem(value);
                break;
        }
    }


    // all of this should be here or in the model
    public OWLLiteral getValue() {
        EditorType type = model.getComponentType(property);

        switch(type){
            case text:      // FALLTHROUGH
            case multiline:
                String text = ((JTextComponent) getEditor()).getText().trim();
                if (text != null && !text.equals("")){
                    return model.getOWLModelManager().getOWLDataFactory().getOWLStringLiteral(text);
                }
                break;
            case combo:
                return (OWLLiteral)((JComboBox) getEditor()).getSelectedItem();
        }
        return null;
    }

    public JComponent getEditor(){
        if (editor == null){
            EditorType type = model.getComponentType(property);

            Set<AWTKeyStroke> newForwardKeys = new HashSet<AWTKeyStroke>();
            Set<AWTKeyStroke> newBackwardKeys = new HashSet<AWTKeyStroke>();

            newForwardKeys.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, InputEvent.CTRL_DOWN_MASK));

            newBackwardKeys.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, InputEvent.CTRL_DOWN_MASK+KeyEvent.SHIFT_DOWN_MASK));
            newBackwardKeys.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, KeyEvent.SHIFT_DOWN_MASK));

            switch(type){
                case text:
                    editor = new JTextField();
                    editor.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));

                    // change the tab key to shift focus instead of inserting a tab character (to help fast input)
                    newForwardKeys.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB, 0));

                    editor.registerKeyboardAction(acceptAction, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.CTRL_DOWN_MASK), 0);
                    editor.registerKeyboardAction(acceptAction, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), 0);
                    break;

                case multiline:
                    JTextArea textArea = new JTextArea();
                    textArea.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED));
                    textArea.setColumns(40);
                    textArea.setWrapStyleWord(true);
                    textArea.setLineWrap(true);
                    textArea.setTabSize(4);
                    editor = textArea;

                    editor.registerKeyboardAction(acceptAction, KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.CTRL_DOWN_MASK), 0);
                    break;
					
               case combo:
					JComboBox combo = new JComboBox();
					
					String labelIRI = "http://www.w3.org/2000/01/rdf-schema#label";
					
					IRI iri = property.getIRI();
					IRI iril = IRI.create(labelIRI);
					
					
					if (iri != null )
					{
						System.out.println(iri.toURI().toString());
					}
					
					try {
					
						OWLModelManager mgr = model.getOWLModelManager();
						//OWLOntologyManager omgr = mgr.getOWLOntologyManager();
						
						OWLDataFactory dfactory = mgr.getOWLDataFactory();
						java.util.Set<OWLOntology> ontologies =	mgr.getOntologies();
						
						//OWLDataFactory dfactory = omgr.getOWLDataFactory();
						
						//java.util.Set<OWLOntology> ontologies =	omgr.getOntologies();
						
						OWLAnnotationProperty owlapropl = dfactory.getOWLAnnotationProperty(iril);
						
						if (ontologies == null)
						{
							System.out.println("OWL ontologies is null \n");
						}
						else
						{
							System.out.println("OWL ontologies size : " + ontologies.size());
						}
						
						java.util.Iterator ontologiesit = ontologies.iterator();
						OWLOntology ontology = (OWLOntology)ontologiesit.next();
						
						//OWLOntology ontology = omgr.loadOntologyFromOntologyDocument(iri);
						
						OWLAnnotationProperty aprop = dfactory.getOWLAnnotationProperty(iri);
						java.util.Set<OWLAxiom> axioms = aprop.getReferencingAxioms(ontology);
						
						if (axioms == null)
						{
							System.out.println("OWL Axioms is null \n");
						}
						else
						{
							System.out.println("OWL Axioms size : " + axioms.size());
						}
						
						java.util.Iterator axiomsit = axioms.iterator();
						while (axiomsit.hasNext()) 
						{
							OWLAxiom ax = (OWLAxiom)axiomsit.next();
							
							if (ax instanceof OWLAnnotationPropertyRangeAxiom) 
							{
								OWLAnnotationPropertyRangeAxiom rax = (OWLAnnotationPropertyRangeAxiom)ax;
								IRI irid = rax.getRange();
								
								if (irid != null)
								{
									System.out.println("Got IRI range");
									
									OWLClass oclass = dfactory.getOWLClass(irid);
									if (oclass != null)
									{
										System.out.println("Got OWL Class " + oclass.getClass().toString());
										
										java.util.Set<OWLAxiom> ocaxioms = oclass.getReferencingAxioms(ontology);
										
										if (ocaxioms == null)
										{
											System.out.println("OWL Axioms is null \n");
										}
										else
										{
											System.out.println("OWL Axioms size : " + ocaxioms.size());
										}
						
										java.util.Iterator iter = ocaxioms.iterator();
										while (iter.hasNext()) 
										{
											OWLAxiom ocax = (OWLAxiom)iter.next();
											AxiomType axType = ocax.getAxiomType();
											
											System.out.println("OWL Axiom Name : " + axType.getName());
											System.out.println("OWL Axiom Type : " + axType.toString());
											
											if (ocax instanceof OWLEquivalentClassesAxiom)  //
											{
												OWLEquivalentClassesAxiom oecaxiom = (OWLEquivalentClassesAxiom)ocax;
												java.util.Set<OWLClassExpression> ocexpr = oecaxiom.getClassExpressions();
												
												if (ocexpr == null)
												{
													System.out.println("OWL Class Expressions is null \n");
												}
												else
												{
													System.out.println("OWL Class Expressions size : " + ocexpr.size());
												}
										
												//find one in set which is of type OWLObjectOneOf
												//getIndividuals() call on it 
												// you will get a set of OWLIndividual objects
												//process each of the objects to get the information
												
												java.util.Iterator ocexpriter = ocexpr.iterator();
												while (ocexpriter.hasNext()) 
												{
													OWLClassExpression ocexp = (OWLClassExpression)ocexpriter.next();
													if (ocexp instanceof OWLObjectOneOf) 
													{
														java.util.Set<OWLNamedIndividual> inds = ocax.getIndividualsInSignature();
														java.util.Iterator ooooiter = inds.iterator();
														
														if (inds == null)
														{
															System.out.println("OWL Named Individuals is null \n");
														}
														else
														{
															System.out.println("OWL Named Individuals size : " + inds.size());
														}
														
														while (ooooiter.hasNext()) 
														{
															OWLNamedIndividual onind = (OWLNamedIndividual)ooooiter.next();
															
															java.util.Set<OWLAnnotation> oindas = onind.getAnnotations(ontology, owlapropl);
															java.util.Iterator oindaiter = oindas.iterator();
														
															if (oindas == null)
															{
																System.out.println("OWL Annotations is null \n");
															}
															else
															{
																System.out.println("OWL Annotations size : " + oindas.size());
															}
															
															while (oindaiter.hasNext()) 
															{
																OWLAnnotation oinda = (OWLAnnotation)oindaiter.next();
																
																if (oinda.getValue() instanceof OWLLiteral) 
																{
																	OWLLiteral val = (OWLLiteral) oinda.getValue();
																	System.out.println(" : OWL Literal : " + val.getLiteral());
																	
																	combo.addItem(new KeyValue(val.getLiteral(), onind.getIRI().toString()));
																}
															}
														}
													}
												}
											}
									
										}
									}
								}
							}
						}
						
					}
					catch (Exception e) {
						
					}
					
					editor = combo;
					
                    break;
            }

            // bind our new focus traversal keys
            editor.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, newForwardKeys);
            editor.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, newBackwardKeys);

            editor.addFocusListener(focusListener);
        }
        return editor;
    }


    public OWLAxiom getAxiom(){
        return annotAxiom;
    }
}
